/*******************************************************************************
 *
 *      Filename: Log.h
 *   Description: System log class to collect log messages from all engine
 *                components.
 *        Author: [kb]ypp
 *    Created at: September 28, 2005
 * Last modified: November 26, 2005
 *
 ******************************************************************************/

#ifndef LOG_H
#define LOG_H

#include "Singleton.h"
#include <iosfwd>
#include <string>

//! @brief System log class.
//!
//! Singleton. Use this class to report about all important system events.
//! Under the Windows OS default `log.txt' file used to store output messages,
//! in other OS's output goes to stderr (by default).
class Log : public Singleton< Log > {
public:
	//! @brief Defines message priority level.
	//!
	//! From the most to less important.
	enum MsgPriority {
		EMERGENCY = 0, //!< Level 0: System is unusable
		ALERT,         //!< Level 1: Action must be taken immediately
		CRITICAL,      //!< Level 2: Critical conditions
		ERROR,         //!< Level 3: Error conditions
		WARNING,       //!< Level 4: Warning conditions
		NOTICE,        //!< Level 5: Normal but significant condition
		INFO,          //!< Level 6: Informational
		DEBUG,         //!< Level 7: Debug-level messages
		NUM_LEVELS     //!< The number of priority levels
	};
	
	//! @brief Put a massage into the log
	friend Log& operator<<( Log &log, const std::string &msg );
	/*
	//! @brief Redirect log output to another stream
	void outputTo( std::ostream &os );
	//! @brief Redirect log output to file with a given name
	void outputTo( const std::string &filename );
	*/
	
protected:
	friend class Singleton< Log >;
	//! @brief Default constructor
	Log();
	//! @brief Virtual destructor
	virtual ~Log();
	
private:
	//! @brief Helper function to write header at the beginning of the log
	void writeHeader();
	
	std::ostream *out; //!< Pointer to output stream
};

//! @brief A helper class to make usage of Log class easier
class LogHelper {
public:
	//! @brief Constructor
	LogHelper( Log::MsgPriority pr, const std::string &file, int line );
	//! @brief Copy-constructor
	LogHelper( const LogHelper &other );
	//! @brief Assignment operator
	const LogHelper& operator=( const LogHelper &other );
	//! @brief Put another message to log stream (with current prefix)
	friend LogHelper& operator<<( LogHelper &lh, const std::string &msg );
	
private:
	std::string prefix; //!< Place to store prefix for all messages
};

// Helper macro's to make Log class more easy-to-use:

/*
//! @brief Write message `msg' to log with given priority
#define LOG( priority, msg ) \
	do { \
		LogHelper helper( priority, __FILE__, __LINE__ ); \
		helper << ( msg ); \
	} while( 0 )
*/

//! @brief Write emergency message `msg' to log
#define LOG_EMERGENCY( msg ) \
	do { \
		LogHelper helper( Log::EMERGENCY, __FILE__, __LINE__ ); \
		helper << ( msg ); \
	} while( 0 )

//! @brief Write alert message `msg' to log
#define LOG_ALERT( msg ) \
	do { \
		LogHelper helper( Log::ALERT, __FILE__, __LINE__ ); \
		helper << ( msg ); \
	} while( 0 )

//! @brief Write critical message `msg' to log
#define LOG_CRITICAL( msg ) \
	do { \
		LogHelper helper( Log::CRITICAL, __FILE__, __LINE__ ); \
		helper << ( msg ); \
	} while( 0 )

//! @brief Write error message `msg' to log
#define LOG_ERROR( msg ) \
	do { \
		LogHelper helper( Log::ERROR, __FILE__, __LINE__ ); \
		helper << ( msg ); \
	} while( 0 )

//! @brief Write warning message `msg' to log
#define LOG_WARNING( msg ) \
	do { \
		LogHelper helper( Log::WARNING, __FILE__, __LINE__ ); \
		helper << ( msg ); \
	} while( 0 )

//! @brief Write notice message `msg' to log
#define LOG_NOTICE( msg ) \
	do { \
		LogHelper helper( Log::NOTICE, __FILE__, __LINE__ ); \
		helper << ( msg ); \
	} while( 0 )

//! @brief Write info message `msg' to log
#define LOG_INFO( msg ) \
	do { \
		LogHelper helper( Log::INFO, __FILE__, __LINE__ ); \
		helper << ( msg ); \
	} while( 0 )

//! @brief Write debug message `msg' to log
#define LOG_DEBUG( msg ) \
	do { \
		LogHelper helper( Log::DEBUG, __FILE__, __LINE__ ); \
		helper << ( msg ); \
	} while( 0 )

#endif // LOG_H
